home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / grepsmc.arc / GREPSMC.C < prev    next >
Text File  |  1986-11-30  |  19KB  |  750 lines

  1. /*
  2.  *
  3.  *
  4.  * The    information  in  this  document  is  subject  to  change
  5.  * without  notice  and  should not be construed as a commitment
  6.  * by Digital Equipment Corporation or by DECUS.
  7.  *
  8.  * Neither Digital Equipment Corporation, DECUS, nor the authors
  9.  * assume any responsibility for the use or reliability of  this
  10.  * document or the described software.
  11.  *
  12.  *    Copyright (C) 1980, DECUS
  13.  *
  14.  *
  15.  * General permission to copy or modify, but not for profit,  is
  16.  * hereby  granted,  provided that the above copyright notice is
  17.  * included and reference made to  the    fact  that  reproduction
  18.  * privileges were granted by DECUS.
  19.  *
  20.  */
  21.  
  22. #define    SMALLC        /* comment out for unix */
  23. #define NOLOWER        /* comment out if lower case passed in command line */
  24. #define    GOODHELP    /* comment out to disable -h option */
  25.  
  26. #ifdef SMALLC
  27. #include <stdiocb.h>    /* addresses, orgs to link to system routines */
  28. #include <libasm.h>    /* addresses, orgs to link to printf, etc.*/
  29. #else
  30. #include <stdio.h>
  31. #endif
  32. /*
  33.  * grep.
  34.  *
  35.  * Original version ran on the Decus compiler or on vms.
  36.  * Converted for BDS compiler (under CP/M-80), 20-Jan-83, by Chris Kern.
  37.  *
  38.  * Converted to IBM PC with CI-C86 C Compiler June 1983 by David N. Smith
  39.  *
  40.  * Converted to Small C Version 2.0 (under CP/M-80) by C. Bingham 860724.1
  41.  * Compiles under BSD 4.2 cc when SMALLC and NOLOWER not defined.
  42.  * Several corrections were made to error messages and pattern checking.
  43.  * In addition, the capability to distinguish upper and lower case letters
  44.  * was added.  However, in CP/M lower case is translated to upper in the
  45.  * command line.  Thus when NOLOWER is defined at compilation, grep assumes
  46.  * all letters are lower case unless escaped by '\' when they are always
  47.  * assumed taken to be upper case.  Similarly, in CP/M, one cannot have
  48.  * imbedded blanks or tabs in an argument on the command line.  Thus when
  49.  * NOLOWER is defined, '_' and '`' are interpreted as blank and tab unless
  50.  * escaped by '\' ('\_' and '\`' ).
  51.  *
  52.  * See below for more information.
  53.  *
  54.  */
  55.  
  56. #ifdef    GOODHELP
  57. char *docs0  = "Grep searches a file for a given pattern.  Execute by";
  58. char *docs1  = "   grep [flags] regular_expression file_list";
  59. char *docs2  = " ";
  60. char *docs3  = "Flags are single characters preceeded by '-':";
  61. char *docs4  = "   -c      Only a count of matching lines is printed";
  62. char *docs5  =
  63.  "   -f      Print file name for matching lines switch; see below";
  64. char *docs6  = "   -n      Each line is preceeded by its line number";
  65. char *docs7  = "   -v      Only print non-matching lines";
  66. char *docs8  = " ";
  67. char *docs9  = "The file_list is a list of files.";
  68. char *docs10 = " ";
  69. char *docs11 = "The file name is printed only if more than one file is named.";
  70. char *docs12 =
  71.  "The -f flag reverses this action (print name if one file, not if more).";
  72. char *docs13 = " ";
  73. char *docs14 = "\0";
  74. #ifdef    SMALLC
  75. int    docs[15];
  76. #else
  77. char    *docs[15];
  78. #endif
  79. #ifdef    NOLOWER
  80. char    *patdoc0  =
  81.  "The regular_expression defines the pattern to search for.  Upper case";
  82. char    *patdoc1  =
  83.  "letters must be preceded by '\\'.";
  84. #else
  85. char    *patdoc0  =
  86.  "The regular_expression defines the pattern to search for.  Upper and";
  87. char    *patdoc1  =
  88.  "lower case are distinguished.";
  89. #endif
  90. char    *patdoc2 = " ";
  91. char    *patdoc3  =
  92.  "x      An ordinary character (not mentioned below) matches that character.";
  93. char    *patdoc4  =
  94.  "'\\'    The backslash quotes any character.  \"\\$\" matches a dollar-sign.";
  95. char    *patdoc5  =
  96. "'$'     A dollar-sign at the end of an expression matches the end of a line.";
  97. char    *patdoc6 =
  98.  "'^'    A circumflex at the beginning of an expression matches the";
  99. char    *patdoc7  =
  100.  "       beginning of a line.  Thus '^$' matches an empty line.";
  101. char    *patdoc8  =
  102.  "'.'    A period matches any character except \"newline\".";
  103. char    *patdoc9  =
  104.  "':a'   A colon matches a class of characters described by the following";
  105. char    *patdoc10 =
  106.  "':d'     character.  \":a\" matches any alphabetic, \":d\" matches digits,";
  107. char    *patdoc11 =
  108.  "':n'     \":n\" matches alphanumerics, \": \" matches spaces, tabs, and";
  109. char    *patdoc12 =
  110.  "': '     other non-printing control characters."; 
  111. char    *patdoc13 =
  112.  "'*'    An expression followed by an asterisk matches zero or more";
  113. char    *patdoc14 =
  114.  "       occurrances of that expression: \"fo*\" matches \"f\"; \"fo\" and";
  115. char    *patdoc15 =
  116.  "       \"foo\"; \"t.*e\" matches \"te\", \"the\", \"table\", etc.";
  117. char    *patdoc16 =
  118.  "'+'    An expression followed by a plus sign matches one or more";
  119. char    *patdoc17 =
  120.  "       occurrances of that expression: \"fo+\" matches \"fo\", not \"f\".";
  121. char    *patdoc18 =
  122.  "'-'    An expression followed by a minus sign matches 0 or 1 occurrances";
  123. char    *patdoc19 =
  124.  "       of the expression. \"te-n\" matches \"tn\" and \"ten\", not \"teen\".";
  125. char    *patdoc20 =
  126.  "'[]'   A string enclosed in square brackets matches any character in";
  127. char    *patdoc21 =
  128.  "       that string, but no others.  If the first character in the";
  129. char    *patdoc22 =
  130.  "       string is a circumflex ('^'); the expression matches any character";
  131. char    *patdoc23 =
  132.  "       except \"newline\" and the characters in the string.  For";
  133. char    *patdoc24 =
  134.  "       example, \"[xyz]\" matches \"x\", \"y\" or \"z\", while \"[^xyz]\"";
  135. char    *patdoc25 =
  136.  "       matches \"a\" or \"b\" but not \"x\".  A range of characters may be";
  137. char    *patdoc26 =
  138.  "       specified by two characters separated by \"-\".  Thus,";
  139. char    *patdoc27 =
  140.  "       [a-z] matches any lower case letter, while [z-a] never matches.";
  141. char    *patdoc28 =
  142.  "The concatenation of regular expressions is a regular expression.";
  143. #ifdef    NOLOWER
  144. char    *patdoc29 =
  145.  "A space must be coded by '_' and a tab by '`'.  To obtain these characters";
  146. char    *patdoc30 =
  147.  "use '\\_' and '\\`'.";
  148. char    *patdoc31 = "\0";
  149. #else
  150. char    *patdoc29 = "\0";
  151. #endif
  152. #ifdef    SMALLC
  153. #ifdef    NOLOWER
  154. int    patdoc[32];
  155. #else
  156. int    patdoc[30];
  157. #endif
  158. #else
  159. #ifdef    NOLOWER
  160. char    *patdoc[32];
  161. #else
  162. char    *patdoc[30];
  163. #endif
  164. #endif
  165. #endif
  166.  
  167. #define LMAX    512
  168. #define PMAX    256
  169. #define ENDSTR '\n'
  170. #define CHARR    1
  171. #define BOL    2
  172. #define EOL    3
  173. #define ANY    4
  174. #define CLASS    5
  175. #define NCLASS    6
  176. #define STAR    7
  177. #define PLUS    8
  178. #define MINUS    9
  179. #define ALPHA    10
  180. #define DIGIT    11
  181. #define NALPHA    12
  182. #define PUNCT    13
  183. #define RANGE    14
  184. #define ENDPAT    15
  185. int    cflag;
  186. int    fflag;
  187. int    nflag;
  188. int    vflag;
  189. int    nfile;
  190. int    debug    =    0;       /* Set for debug code      */
  191. char    *pp;
  192. char    lbuf[LMAX];
  193. char    pbuf[PMAX];
  194. /*******************************************************/
  195. main(argc, argv)
  196. int    argc;
  197. #ifdef    SMALLC
  198. int    argv[]; /* no *char arrays in small c*/
  199. #else
  200. char    *argv[];
  201. #endif
  202. {
  203.    char   *p;
  204.    int    c, i;
  205.    int           gotpattern;
  206.    FILE        *f;
  207.    cflag = fflag = nflag = vflag = debug = 0;
  208. #ifdef    GOODHELP
  209.    setdocs();
  210.    setpatdoc();
  211. #endif
  212.    if (argc <= 1)
  213.       usage("No arguments");
  214.    nfile = argc-1;
  215.    gotpattern = 0;
  216.    for (i=1; i < argc; ++i) {
  217.       p = argv[i];
  218.       if (*p == '-') {
  219.      ++p;
  220.      while ((c = *p++)) {
  221.         switch(tolower(c)) {
  222. #ifdef    GOODHELP
  223.         case 'h':
  224.            help(docs);
  225.            help(patdoc);
  226.            break;
  227. #endif
  228.         case 'c':
  229.            ++cflag;
  230.            break;
  231.         case 'd':
  232.            ++debug;
  233.            break;
  234.         case 'f':
  235.            ++fflag;
  236.            break;
  237.         case 'n':
  238.            ++nflag;
  239.            break;
  240.         case 'v':
  241.            ++vflag;
  242.            break;
  243.         default:
  244.            usage("Unknown flag");
  245.         }
  246.      }
  247.      argv[i] = 0;
  248.      --nfile;
  249.       } else if (!gotpattern) {
  250.      compile(p);
  251.      argv[i] = 0;
  252.      ++gotpattern;
  253.      --nfile;
  254.       }
  255.    }
  256.    if (!gotpattern)
  257.       usage("No pattern");
  258.    if (nfile == 0)
  259.       grep(stdin, "stdin");
  260.    else {
  261.       fflag = fflag ^ (nfile > 1);
  262.       for (i=1; i < argc; ++i) {
  263.      if ((p = argv[i])) {
  264.         if ((f=fopen(p, "r")) == NULL)
  265.            cant(p);
  266.         else {
  267.            grep(f, p);
  268.            fclose(f);
  269.         }
  270.      }
  271.       }
  272.    }
  273. }
  274. /*******************************************************/
  275. cant(s)
  276. char *s;
  277. {
  278.    fprintf(stderr,"grep: cannot open %s\n",s);
  279. }
  280. /*******************************************************/
  281. #ifdef    GOODHELP
  282. help(hp)
  283. #ifdef    SMALLC
  284. int hp[];
  285. #else
  286. char    *hp[];
  287. #endif
  288. /*
  289.  * Give good help
  290.  */
  291. {
  292.    int   i;
  293.    char    *line;
  294.    for (i=0,line=hp[0]; *line; line=hp[++i])
  295.    {
  296.       fprintf(stderr,"%s\n",hp[i]);
  297.    }
  298. }
  299. #endif
  300. /*******************************************************/
  301. usage(s)
  302. char    *s;
  303. {
  304.    fprintf(stderr,"grep: %s\n",s);
  305. #ifdef    GOODHELP
  306.    fputs(
  307.    "Usage: grep [-cfnvh] pattern [ file1 [ file2 ... ] ] [ > file ]\n",stderr);
  308.    fputs("   or: grep [-cfnvh] pattern < file1 [ > file ]\n",stderr);
  309.    fputs("To get help, use   grep -h\n",stderr);
  310. #else
  311.    fputs(
  312.    "Usage: grep [-cfnv] pattern [ file1 [ file2 ... ] ] [ > file ]\n",stderr);
  313.    fputs("   or: grep [-cfnv] pattern < file1 [ > file ]\n",stderr);
  314. #endif
  315.    exit(1);
  316. }
  317. /*******************************************************/
  318. compile(source)
  319. char       *source;   /* Pattern to compile        */
  320. /*
  321.  * Compile the pattern into global pbuf[]
  322.  */
  323. {
  324.    char  *s;          /* Source string pointer       */
  325.    char  *lp;          /* Last pattern pointer       */
  326.    int   c;          /* Current character       */
  327.    int          o;          /* Temp               */
  328.    char       *spp;       /* Save beginning of pattern */
  329. #ifdef    SMALLC
  330.    int      cclass();  /* Compile class routine   */
  331. #else
  332.    char   *cclass();
  333. #endif
  334.    s = source;
  335.    if (debug)
  336.       fprintf(stderr,"Pattern = \"%s\"\n", s);
  337.    pp = pbuf;
  338.    while ((c = *s++)) {
  339.       /*
  340.        * STAR, PLUS and MINUS are special.
  341.        */
  342.       if (c == '*' || c == '+' || c == '-') {
  343.      if (pp == pbuf ||
  344.           (o = *lp) == BOL ||
  345.           o == EOL ||
  346.           o == STAR ||
  347.           o == PLUS ||
  348.           o == MINUS
  349.      )
  350.           badpat("Illegal occurrance op.", source, s);
  351.      store(ENDPAT);
  352.      store(ENDPAT);
  353.      spp = pp;         /* Save pattern end     */
  354.      while (--pp > lp)     /* Move pattern down     */
  355.         *pp = *(pp-1);     /* one byte         */
  356.     if(c == '*') *pp = STAR;
  357.     else
  358.     {
  359.         if(c == '-') *pp = MINUS;
  360.         else *pp = PLUS;
  361.     }
  362.      pp = spp;         /* Restore pattern end  */
  363.      continue;
  364.       }
  365.       /*
  366.        * All the rest.
  367.        */
  368.       lp = pp;           /* Remember start       */
  369.       switch(c) {
  370.       case '^':
  371.      store(BOL);
  372.      break;
  373.       case '$':
  374.      store(EOL);
  375.      break;
  376.       case '.':
  377.      store(ANY);
  378.      break;
  379.       case '[':
  380.      s = cclass(source, s);
  381.      break;
  382.       case ':':
  383.      if (*s) {
  384.         c = *s++;
  385.         switch(tolower(c)) {
  386.         case 'a':
  387.            store(ALPHA);
  388.            break;
  389.         case 'd':
  390.            store(DIGIT);
  391.            break;
  392.         case 'n':
  393.            store(NALPHA);
  394.            break;
  395.         case ' ':
  396.            store(PUNCT);
  397.            break;
  398.         default:
  399.            badpat("Unknown : type", source, s);
  400.         }
  401.         break;
  402.      }
  403.      else     badpat("No : type", source, s);
  404.       case '\\':
  405.      if (*s)
  406.         c = *s++;
  407. #ifdef    NOLOWER
  408.      store(CHARR);
  409.      store(c);
  410.      break;
  411. #endif
  412.       default:
  413. #ifdef    NOLOWER
  414.      switch(c)
  415.      {
  416.      case '_':
  417.         c = ' ';
  418.         break;
  419.      case '`':
  420.         c = '\t';
  421.         break;
  422.      default:
  423.         c = tolower(c);
  424.      }
  425. #endif
  426.      store(CHARR);
  427.      store(c);
  428.       }
  429.    }
  430.    store(ENDPAT);
  431.    store(0);            /* Terminate string     */
  432.    if (debug) {
  433.       for (lp = pbuf; lp < pp;) {
  434.      if ((c = (*lp++ & 255)) < ' ')
  435.         fprintf(stderr,"%2xh ", c);
  436.      else
  437.        fprintf(stderr,"%c ", c);
  438.       }
  439.       putc('\n',stderr);
  440.    }
  441. }
  442. /*******************************************************/
  443. /*char *    (not legal for Small C) */
  444. #ifdef    SMALLC
  445. cclass(source, src)
  446. #else
  447. char *cclass(source, src)
  448. #endif
  449. char       *source;   /* Pattern start -- for error msg.      */
  450. char       *src;      /* Class start           */
  451. /*
  452.  * Compile a class (within [])
  453.  */
  454. {
  455.    char   *s;          /* Source pointer    */
  456.    char   *cp;       /* Pattern start       */
  457.    int    c;          /* Current character */
  458.    int           o;          /* Temp           */
  459.    s = src;
  460.    o = CLASS;
  461.    if (*s == '^') {
  462.       ++s;
  463.       o = NCLASS;
  464.    }
  465.    store(o);
  466.    cp = pp;
  467.    store(0);                  /* Byte count     */
  468.    while ((c = *s++))
  469.    {
  470.       if (c == ']' && pp - cp > 1)
  471.          break;
  472.       if (c == '\\') {                /* Store quoted char    */
  473.      if ((c = *s++) == '\0')      /* Gotta get something  */
  474.         badpat("Class terminates badly", source, --s);
  475.      else     store(c);
  476.       }
  477.       else if ((c == '-') &&
  478.         ((pp - cp) > 1) && (*s != ']') && (*s != '\0') )
  479.       {
  480.      c = *(pp-1);         /* Range start     */
  481.      *(pp-1) = RANGE;     /* Range signal    */
  482.      store(c);         /* Re-store start  */
  483.      c = *s++;               /* Get end char    */
  484. #ifdef    NOLOWER
  485.      switch(c)
  486.      {
  487.      case '\\':
  488.             c = *s++;
  489.         if(c == '\0')
  490.             badpat("Class terminates badly", source, --s);
  491.         break;
  492.     case '_':
  493.         c  = ' ';
  494.         break;
  495.     case '`':
  496.             c = '\t';
  497.         break;
  498.     default:
  499.         c = tolower(c);
  500.      }
  501. #else
  502.      if(c == '\\')            /* Store quoted character */
  503.      {
  504.         if((c = *s++) == '\0')
  505.            badpat("Class terminates badly", source, --s);
  506.      }
  507. #endif
  508.      store(c);     /* Store it        */
  509.       }
  510.       else
  511.       {
  512. #ifdef    NOLOWER
  513.      switch (c)
  514.      {
  515.      case '_':
  516.         c = ' ';
  517.         break;
  518.      case '`':
  519.         c = '\t';
  520.         break;
  521.      default:
  522.         c = tolower(c);
  523.      }
  524. #endif
  525.      store(c);     /* Store normal char */
  526.       }
  527.    }
  528.    if (c != ']')
  529.       badpat("Unterminated class", source, --s);
  530.    if ((c = (pp - cp)) >= 256)
  531.       badpat("Class too large", source, s);
  532.    *cp = c;
  533.    return(s);
  534. }
  535. /*******************************************************/
  536. store(op)
  537. char    op;
  538. {
  539.    if (pp >= &pbuf[PMAX])
  540.       error("Pattern too complex\n");
  541.    *pp++ = op;
  542. }
  543. /*******************************************************/
  544. badpat(message, source, stop)
  545. char  *message;       /* Error message */
  546. char  *source;          /* Pattern start */
  547. char  *stop;          /* Pattern end   */
  548. {
  549.    fprintf(stderr,"grep: %s, pattern is \"%s\"\n",message,source);
  550.    fprintf(stderr,"      Stopped at byte %d \'%c\'\n",
  551.     stop-source,*(stop-1));
  552.    fputs("'\n",stderr);
  553.    error("grep: Bad pattern\n");
  554. }
  555. /*******************************************************/
  556. grep(fp, fn)
  557. FILE       *fp;       /* File to process        */
  558. char       *fn;       /* File name (for -f option)  */
  559. /*
  560.  * Scan the file for the pattern in pbuf[]
  561.  */
  562. {
  563.    int lno, count, m;
  564.    lno = 0;
  565.    count = 0;
  566.    while (fgets(lbuf, LMAX, fp)) {
  567.       ++lno;
  568.       m = match();
  569.       if ((m && !vflag) || (!m && vflag)) {
  570.      ++count;
  571.      if (!cflag) {
  572.         if (fflag) 
  573.            printf("%s:",fn);
  574.         if (nflag)
  575.            printf("%d:", lno);
  576.         printf("%s", lbuf);
  577.      }
  578.       }
  579.    }
  580.    if (cflag) {
  581.       if (fflag)
  582.      printf("%s: ",fn);
  583.       printf("%d\n", count);
  584.    }
  585. }
  586. /*******************************************************/
  587. match()
  588. /*
  589.  * Match the current line (in lbuf[]), return 1 if it does.
  590.  */
  591. {
  592.    char   *l;          /* Line pointer        */
  593. #ifdef    SMALLC
  594.    int pmatch();
  595. #else
  596.    char *pmatch();
  597. #endif
  598.    for (l = lbuf; *l; l++) {
  599.       if (pmatch(l, pbuf))
  600.      return(1);
  601.    }
  602.    return(0);
  603. }
  604. /*******************************************************/
  605. #ifdef    SMALLC
  606. pmatch(line, pattern)
  607. #else
  608. char  *pmatch(line, pattern)
  609. #endif
  610. char           *line;     /* (partial) line to match      */
  611. char           *pattern;  /* (partial) pattern to match   */
  612. {
  613.    char   *l;          /* Current line pointer          */
  614.    char   *p;          /* Current pattern pointer      */
  615.    char   c;          /* Current character          */
  616.    char        *e;          /* End for STAR and PLUS match  */
  617.    int           op;          /* Pattern operation          */
  618.    int           n;          /* Class counter              */
  619.    char        *are;      /* Start of STAR match          */
  620.    l = line;
  621.    if (debug > 1)
  622.       fprintf(stderr,"pmatch(\"%s\")\n", line);
  623.    p = pattern;
  624.    while ((op = *p++) != ENDPAT) {
  625.       if (debug > 1)
  626.      fprintf(stderr,"byte[%d] = %xh, '%c',op = %xh\n",
  627.              l-line, *l, *l, op);
  628.       switch(op) {
  629.       case CHARR:
  630.      if (*l != *p++)
  631.         return(0);
  632.      l++;
  633.      break;
  634.       case BOL:
  635.      if (l != lbuf)
  636.         return(0);
  637.      break;
  638.       case EOL:
  639.      if (*l != ENDSTR)
  640.         return(0);
  641.      break;
  642.       case ANY:
  643.      if (*l++ == ENDSTR)
  644.         return(0);
  645.      break;
  646.       case DIGIT:
  647.      if ((c = *l++) < '0' || (c > '9'))
  648.         return(0);
  649.      break;
  650.       case NALPHA:
  651.       case ALPHA:
  652.      c = *l++;
  653.      if (c >= 'a' && c <= 'z')
  654.         break;
  655.      else if (c >= 'A' && c <= 'Z')
  656.         break;
  657.      else if(op == NALPHA && c >= '0' && c <= '9')
  658.         break;
  659.      return(0);
  660.       case PUNCT:
  661.      c = *l++;
  662.      if (c == ENDSTR || c > ' ')
  663.         return(0);
  664.      break;
  665.       case CLASS:
  666.       case NCLASS:
  667.      c = *l++;
  668.      n = *p++ & 255;
  669.      do {
  670.         if (*p == RANGE) {
  671.            p += 3;
  672.            n -= 2;
  673.            if (c >= *(p-2) && c <= *(p-1))
  674.           break;
  675.         }
  676.         else if (c == *p++)
  677.            break;
  678.      } while (--n > 1);
  679.      if ((op == CLASS) == (n <= 1))
  680.         return(0);
  681.      if (op == CLASS)
  682.         p += n - 2;
  683.      break;
  684.       case MINUS:
  685.      e = pmatch(l, p);     /* Look for a match    */
  686.      while (*p++ != ENDPAT); /* Skip over pattern    */
  687.      if (e)          /* Got a match?    */
  688.         l = e;         /* Yes, update string    */
  689.      break;          /* Always succeeds    */
  690.       case PLUS:         /* One or more ...    */
  691.      if ((l = pmatch(l, p)) == 0)
  692.         return(0);         /* Gotta have a match    */
  693.       case STAR:         /* Zero or more ...    */
  694.      are = l;         /* Remember line start */
  695.      while ((*l != ENDSTR) && ((e = pmatch(l, p))))
  696.         l = e;         /* Get longest match    */
  697.      while (*p++ != ENDPAT); /* Skip over pattern    */
  698.      while (l >= are) {     /* Try to match rest    */
  699.         if ((e = pmatch(l, p)))
  700.            return(e);
  701.         --l;         /* Nope, try earlier    */
  702.      }
  703.      return(0);         /* Nothing else worked */
  704.       default:
  705.      fprintf(stderr,"Bad op code %d\n", op);
  706.      error("Cannot happen -- match\n");
  707.       }
  708.    }
  709.    return(l);
  710. }
  711. /*******************************************************/
  712. error(s)
  713. char *s;
  714. {
  715.    fputs(s,stderr);
  716.    exit(1);
  717. }
  718. tolower(c)
  719. char    c;
  720. {
  721.     if(c >= 'A' && c <= 'Z')c = c + ('a' - 'A');
  722.     return c;
  723. }
  724. #ifdef    GOODHELP
  725. setdocs()
  726. {
  727.     docs[0] = docs0;docs[1] = docs1;docs[2] = docs2;
  728.     docs[3] = docs3;docs[4] = docs4;docs[5] = docs5;
  729.     docs[6] = docs6;docs[7] = docs7;docs[8] = docs8;
  730.     docs[9] = docs9;docs[10]=docs10;docs[11]=docs11;
  731.     docs[12]=docs12;docs[13]=docs13;docs[14]=docs14;
  732. }
  733. setpatdoc()
  734. {
  735.     patdoc[0] = patdoc0;patdoc[1] = patdoc1;patdoc[2] = patdoc2;
  736.     patdoc[3] = patdoc3;patdoc[4] = patdoc4;patdoc[5] = patdoc5;
  737.     patdoc[6] = patdoc6;patdoc[7] = patdoc7;patdoc[8] = patdoc8;
  738.     patdoc[9] = patdoc9;patdoc[10]=patdoc10;patdoc[11]=patdoc11;
  739.     patdoc[12]=patdoc12;patdoc[13]=patdoc13;patdoc[14]=patdoc14;
  740.     patdoc[15]=patdoc15;patdoc[16]=patdoc16;patdoc[17]=patdoc17;
  741.     patdoc[18]=patdoc18;patdoc[19]=patdoc19;patdoc[20]=patdoc20;
  742.     patdoc[21]=patdoc21;patdoc[22]=patdoc22;patdoc[23]=patdoc23;
  743.     patdoc[24]=patdoc24;patdoc[25]=patdoc25;patdoc[26]=patdoc26;
  744.     patdoc[27]=patdoc27;patdoc[28]=patdoc28;patdoc[29]=patdoc29;
  745. #ifdef  NOLOWER
  746.     patdoc[30]=patdoc30;patdoc[31]=patdoc31;
  747. #endif
  748. }
  749. #endif
  750.